#ifndef ELEMENT_H
#define ELEMENT_H

#include <QString>
#include <QObject>
#include <QDebug>

#define TREE_DEBUG

#ifdef TREE_DEBUG
#include <iostream>
using namespace std;
#endif

class Node;

template<class KEY, class DATA> class Element
{
public:
    KEY key;        // ключ
    DATA data;      // значение (данные)
    Node* subtree;  // указатель на поддерево

public:
    bool operator >   (Element& other) const { return key >  other.key; }
    bool operator <   (Element& other) const { return key <  other.key; }
    bool operator >=  (Element& other) const { return key >= other.key; }
    bool operator <=  (Element& other) const { return key <= other.key; }
    bool operator ==  (Element& other) const { return key == other.key; }

    Element& operator = (const Element& other) {
        key = other.key;
        data = other.data;
        subtree = other.subtree;
        return *this;
    }

    Element () { subtree = NULL; }

    bool valid () const { return subtree != reinterpret_cast<Node*> (-1); }
    void invalidate ()  { subtree = reinterpret_cast<Node*> (-1);         }

    // это для отладки? + Elem::dump()
    void dump () { qDebug() << "key = " << key /* << " sub = " << subtree*/ << "   ";}
};

//typedef Element<int, string> Elem;
typedef int KeyType;
typedef QString ValueType;

// Element QObject wrapper
class Elem : public QObject
{
    Q_OBJECT
public:
    bool operator >   (Elem& other) const { return mData.operator > (other.mData); }
    bool operator <   (Elem& other) const { return mData.operator < (other.mData); }
    bool operator >=  (Elem& other) const { return mData.operator >= (other.mData); }
    bool operator <=  (Elem& other) const { return mData.operator <= (other.mData); }
    bool operator ==  (Elem& other) const { return mData.operator == (other.mData); }

    operator Element<KeyType, ValueType>& () { return mData; }

    Elem& operator = (const Elem& other)
    {
        QObject::setParent(other.parent());
        mData = other.mData;
        return *this;
    }

    Elem() :
        mData()
    {}

    Elem(const Elem& other) :
        QObject(other.parent()),
        mData(other.mData)
    {}

    bool valid () const { return mData.valid(); }
    void invalidate() { mData.invalidate(); }
    void dump() { mData.dump(); }

    KeyType key() const { return mData.key; }
    void setKey(const KeyType& key)
    {
        if ( key != mData.key )
        {
            mData.key = key;
            emit keyChanged(mData.key);
        }
    }

    ValueType data() const { return mData.data; }

    Node* subtree() const { return mData.subtree; }
    void setSubtree(Node* subtree)
    {
        if ( subtree != mData.subtree )
        {
            mData.subtree = subtree;
            emit subtreeChanged();
        }
    }


signals:
    // TODO: написать еще, emit
    void keyChanged(const KeyType& newKey);
    void dataChanged(const ValueType& newData);
    void subtreeChanged();

public slots:
    void setData(const QString& data)
    {
        if ( data != mData.data )
        {
            mData.data = data;
            emit dataChanged(mData.data);
        }
    }

private:
    Element<KeyType, ValueType> mData;
};

#endif // ELEMENT_H
